#!/bin/sh
# - events
# - revents
# - delay
# - duration
# - command
# - per_socket
# - per_die
# - interval_ms
# - rmetrics
# - metrics
# - metric_only
# - list_pmu_events

. $LKP_SRC/lib/env.sh
. $LKP_SRC/lib/common.sh
. $LKP_SRC/lib/debug.sh
. $LKP_SRC/lib/reproduce-log.sh

: "${interval_ms:=1000}"
: "${delay:=0}"
: "${duration:=0}"
: "${metric_only:=0}"

set_perf_path "/lkp/benchmarks/perf/perf"
export perf

# perf may consume lots of fd
ulimit -n 102400

perf_reg_num()
{
	dmesg | grep -e 'Performance Events' -C 3 | sed -ne '1,$s/.*generic registers:\s*\([0-9]\+\)/\1/p'
}

avail_events=" $($LKP_SRC/bin/perf-events hardware cache) "
check_event()
{
	[ "${avail_events#* $1 }" != "$avail_events" ]
}

check_add_events()
{
	in_events=$(echo "$*" | tr '{},' '   ')
	for event in $in_events; do
		check_event $event || return 1
	done
	events="$events$*,"
}

if [ -n "$revents" ]; then
	events="$revents"
elif [ -n "$events" ]; then
	events=$($LKP_SRC/bin/perf-events ${events//,/ })
	[ -n "$events" ] || die "Events are empty"
elif [ -n "$rmetrics" ]; then
	metrics="$rmetrics"
else
	# Each event should be used only once, because we have no
	# event group support in stats/perf-stat yet
	reg_num=$(perf_reg_num)
	if [ "0$reg_num" -lt 4 ]; then
		check_add_events '{cpu-cycles,instructions,cache-references,cache-misses}'
		check_add_events '{branch-instructions,branch-misses}'
	else
		check_add_events '{cpu-cycles,instructions,cache-references,cache-misses,branch-instructions,branch-misses}'
	fi
	check_add_events '{dTLB-loads,dTLB-load-misses}'
	check_add_events '{dTLB-stores,dTLB-store-misses}'
	check_add_events '{iTLB-loads,iTLB-load-misses}'
	check_add_events '{node-loads,node-load-misses}'
	check_add_events '{node-stores,node-store-misses}'
	events="${events}\
cpu-clock,task-clock,\
page-faults,context-switches,\
cpu-migrations,\
minor-faults,major-faults"
fi

[ -n "$events" ] && opt_events="-e $(echo $events | sed 's/[ ,]\+/ -e /g')"
[ -n "$metrics" ] && opt_metrics="-M $(echo $metrics)"

. $LKP_SRC/lib/wait.sh

setup_wait

parse_bool -q "$per_socket" && opts="$opts --per-socket"
parse_bool -q "$per_die" && opts="$opts --per-die"
parse_bool -q "$metric_only" && opts="$opts --metric-only"

disable_nmi_watchdog

$perf -v || die 'perf command failed'
# since 75998bb263 ("perf stat: Fix --no-scale"), -c is removed

[ -n "$list_pmu_events" ] && $perf list > "$TMP_RESULT_ROOT/perf-pmu-events"

[ "$duration" -gt 0 ] && timeout="--timeout $((delay + duration))"

log_cmd $SUDO $perf stat -a --scale -I "$interval_ms" -x ',' $opt_events  $opt_metrics --log-fd 1 $opts -D $((delay * 1000)) -- $LKP_SRC/bin/wait.sh $WAIT_POST_TEST_CMD $timeout
